package core;

import static org.junit.Assert.*;

import java.io.File;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.junit.BeforeClass;
import org.junit.Test;

public class PublisherTest {
	// Constantes.
	private static final String name_publisher = "publicador-test";
	private static final String tests_path = "tests_publisher/";
	private static final String fichero_permisos = "clave_sin_permisos.bin";
	private static final String privkey_fname = "keys/publicador-private.key";
	private static final String publkey_fname = "keys/publicador-public.key";
	
	// Atributo de las pruebas, publicador que se usará entre pruebas.
	private static Publisher pub;
	
	// Funciones privadas para las pruebas.
	/**
	 * Borra el fichero con ese nombre si existia.
	 * @param name: El path del fichero a borrar.
	 */
	private static void borraFichero(String name) {
		File fd;
		
		fd = new File(name);
		if (fd.exists())
			fd.delete();
	}

	@BeforeClass  	
	public static void setUpClass() throws Exception {
		String absprivname, abspubname, abspubliname;
		
		// Antes de comenzar pruebas comprobamos que en la carpeta de pruebas
		// no existen ficheros con los nombres reservados, si existen los
		// borramos, así que andense con ojo con lo que ponen ahí... sin
		// contemplaciones :).
		absprivname = tests_path + name_publisher + "-" +
					  Publisher.GENERIC_PRIVATEKEY_FNAME;
		abspubname = tests_path + name_publisher + "-" +
		  			 Publisher.GENERIC_PUBLICKEY_FNAME;
		abspubliname = tests_path+name_publisher+".pub";
		borraFichero(absprivname);
		borraFichero(abspubname);
		borraFichero(abspubliname);
		
		
		// Asignacion de permisos		
		File ficheropermisos = new File(tests_path+fichero_permisos);
		ficheropermisos.setReadable(false);

		
	}
	
	// Funciones de test.
	
	@Test
	public void testPublisher() {
		Publisher pub2;
		
		// Caso correcto, se crea el objeto Publisher con nombre y path.
		try {
			pub = new Publisher(name_publisher, tests_path);
		}
		catch (Exception e) {
			fail("No se deberia haber lanzado excepción.");
		}
		
		// Caso correcto se lanza una excepción porque los ficheros de claves
		// ya existían.
		try {
			pub2 = new Publisher(name_publisher, tests_path);
			fail("Se debería haber lanzado una excepción.");
			
			// Esta linea no sirve de nada, nunca se llegará a ejecutar, la
			// pongo para quitarle un warning y que el compilador deje de
			// llorar... a los compiladores hay que tratarlos con cariño.
			pub2.getName();
		}
		catch (Exception e) {
			;
		}
		
		// Caso correcto, se crea el publicador solo con el nombre.
		try {
			pub2 = new Publisher(name_publisher);
		}
		catch (Exception e) {
			fail("No debería haberse lanzado una excepción.");
		}
		
		// Caso incorrecto, el path no existe... no hagan la gracieta de
		// crear el path ¬¬.
		try {
			pub2 = new Publisher(name_publisher, "path_inexistente/");
			fail("Se debería haber lanzado una excepción");
		}
		catch (Exception e) {
			;
		}
	}
	
	@Test
	public void testGetName() throws IOException, ClassNotFoundException {
		try{
			String pubesperado = "Nolla";
			// Recuperamos el publisher
			Publisher newpub = new Publisher(pubesperado);
			assertArrayEquals(pubesperado.toCharArray(),newpub.getName().toCharArray());	
		}catch(Exception e){
			fail("Error al recuperar nombre");
		}
		
	}

	@Test
	public void testGetPublicKey() throws IOException {
		try{
			// Creamos un publisher
			pub.save(tests_path);
			
			// Creamos otro publisher leyendo el salvado
			Publisher pub2 = Publisher.createPublisher(tests_path+name_publisher+".pub");
			
			// Recuperamos ambas claves publicas
			PublicKey pubkey1 = pub.getPublicKey();
			PublicKey pubkey2 = pub2.getPublicKey();
			
			byte[] pubkey1bytes = pubkey1.getEncoded();
			byte[] pubkey2bytes = pubkey2.getEncoded();
			
			assertEquals(Util.byteArray2HexStr(pubkey1bytes),Util.byteArray2HexStr(pubkey2bytes));
		}catch(Exception e){
			fail("Error al recuperar clave privada"+tests_path+name_publisher+".pub");
		}
		
	}

	@Test
	public void testGetPrivateKey() {
		try{
			// Creamos un publisher
			//Publisher priv1 = new Publisher(name_publisher,tests_path);
			pub.save(tests_path);
			
			// Creamos otro publisher leyendo el salvado
			Publisher priv2 = Publisher.createPublisher(tests_path+name_publisher+".pub");
			
			// Recuperamos ambas claves publicas
			PrivateKey privkey1 = pub.getPrivateKey();
			PrivateKey privkey2 = priv2.getPrivateKey();
			
			byte[] privkey1bytes = privkey1.getEncoded();
			byte[] privkey2bytes = privkey2.getEncoded();
			
			assertEquals(Util.byteArray2HexStr(privkey1bytes),Util.byteArray2HexStr(privkey2bytes));	
		}catch(Exception e){
			fail("Error al recuperar clave privada");
		}
	}

	
	@Test
	public void testImportPublicKey() {
		try{
			/*
			 * NO ACABO DE VER CLARO QUE LA COMPROBACION SEA LA CORRECTA 
			 * */
			pub.importPublicKey(publkey_fname);
			pub.save(tests_path);
			Publisher publicador = Publisher.createPublisher(tests_path+name_publisher+".pub");
			borraFichero(tests_path+"testImportPublicKey.pub");
			assertEquals(pub.getPublicKey(),publicador.getPublicKey());
			
		}catch(Exception e){
			fail("Error al importar clave publica "+e.getMessage());
		}
		
	}

	@Test
	public void testImportPrivateKey() {
		try{
			//Publisher publicador = new Publisher("Nolla");
			// Le pasamos un password vacio, no va cifrado
			pub.importPrivate(privkey_fname, "");
			pub.save(tests_path);
			Publisher publicador = Publisher.createPublisher(tests_path+name_publisher+".pub");
			assertEquals(pub.getPrivateKey(),publicador.getPrivateKey());
			borraFichero(tests_path+"testImportPrivateKey.pub");
		}catch(Exception e){
			fail("Error al importar clave privada");
		}
	}

	@Test
	public void testSalvarPublisher() throws IOException, ClassNotFoundException {
		// Caso correcto
		try{
			// Guardamos el publisher - Salvad al publisher Ryan xDDD
			pub.save(tests_path);
			// Lo leemos
			Publisher pub_leido = new Publisher();
			pub_leido = Publisher.createPublisher(tests_path+name_publisher+".pub");
			// Y comprobamos que el nombre coincida
			borraFichero(tests_path+"testSalvarPublisher.pub");
			assertEquals(pub.getName(), pub_leido.getName());
		}catch(Exception e)
		{
			fail("Error al salvar el publisher");
		}
		// Caso incorrecto, el fichero no existe
		try{
			Publisher pub_leido = new Publisher();
			pub_leido = Publisher.createPublisher(tests_path+"I'mchargingmahlazeeerrr!.bin");
			assertEquals(pub.getName(), pub_leido.getName());
			fail("No existe el fichero");
		}catch(IllegalArgumentException e){
			
		}catch (Exception e) {
		fail("La excepcion no es la correcta");
		}
		// Caso incorrecto, no se puede leer el fichero
		try{
			Publisher pub_leido = new Publisher();
			pub_leido = Publisher.createPublisher(tests_path+fichero_permisos);
			assertEquals(pub.getName(), pub_leido.getName());
			// Para evitar problemas con las pruebas, al copiar, etc
			File ficheropermisos = new File(tests_path+fichero_permisos);
			ficheropermisos.setReadable(true);
			fail("No hay permisos de lectura");
		}catch(IllegalArgumentException e){
			
		}catch (Exception e) {
		fail("La excepcion no es la correcta");
		}
	} 

	@Test
	public void testCreatePublisher() throws IOException {
		try{
			//Publisher publicadorcreado = new Publisher("TestCreatePublisher",tests_path);
			pub.save(tests_path);
			Publisher publicadorleido = Publisher.createPublisher(tests_path+name_publisher+".pub");
			assertEquals(pub.getPrivateKey(), publicadorleido.getPrivateKey());
			borraFichero(tests_path+name_publisher+".pub");
		}catch(Exception e){
			fail("Error al crear publisher");
		}
	}
	
	@Test
	public void testRemove() {
		try {
			Publisher publisher = new Publisher("pub-temporal",tests_path);
			publisher.save(tests_path);
			File file = new File(tests_path+"pub-temporal-public.key");
			file.delete();
			file = new File(tests_path+"pub-temporal-private.key");
			file.delete();
			if(!publisher.remove(tests_path)) {
				fail("No se borró el archivo.... wuawuawuawuaaaaa");
			}	
		}catch(Exception e){
			e.printStackTrace();
			fail("Fallo en testRemove");
		}
	}
}
